/**
 * File:   Launcher.java
 * Author: Gvennet
 */
package gui.main;

import dht.cleaners.*;
import dht.identifier.identifier.Identifier;
import dht.network.Network;
import dht.network.NetworkListener;
import dht.node.*;

import javax.swing.*;
import java.io.IOException;
import java.net.InetAddress;
import java.text.ParseException;
import java.util.concurrent.ScheduledThreadPoolExecutor;

/**
 * todo write javadoc
 */
public final class Launcher
{

	private static ScheduledThreadPoolExecutor scheduledExecutor = new ScheduledThreadPoolExecutor(10);

	private Launcher()
	{
	}

	public static void main(String[] args)
	{


		SwingUtilities.invokeLater(new Runnable()
		{
			//@Override
			public void run()
			{

				LauncherDialog launcherDialog = new LauncherDialog();
				launcherDialog.setVisible(true);
				launcherDialog.dispose();


				if (launcherDialog.getAnswer().equals("Ok"))
				{
					InetAddress ia = launcherDialog.getIpAddress();
					int port = launcherDialog.getPort();

					scheduledExecutor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
					scheduledExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);

					Identifier id;
					try
					{
						id = launcherDialog.getId();
					}
					catch (ParseException e)
					{
						id = null;
					}

					Network network = new Network(ia, port, scheduledExecutor, id, launcherDialog.getTimeout());

					NodeModelCleaner cleaner;

					switch (launcherDialog.getCleaner())
					{
						case 3:
							cleaner = new WithoutCleaner();
							break;
						case 1:
							cleaner = new SimpleCleaner(network);
							break;

						case 2:
							cleaner = new ComplexCleaner(network.getLocalId());
							break;

						case 0:
							cleaner = new TreeCleaner(network.getLocalId());
							break;

						default:
							throw new AssertionError("Неизвестный тип оптимизации таблицы маршрутизации");
					}


					DHTNodeModel nodeModel = new DHTNodeModel(launcherDialog.getMaxNodes(), scheduledExecutor, cleaner);
					cleaner.setNodeModel(nodeModel);
					nodeModel.cleaning();

					long statisticsPeriod = launcherDialog.getStatisticsPeriod();
					if (statisticsPeriod < Long.MAX_VALUE)
					{
						nodeModel.startStatisticsGathering(statisticsPeriod);
					}
					DHTDataModel dataModel = new DHTDataModel(scheduledExecutor, launcherDialog.getStorageTime());
					dataModel.removingOlds();
					if (statisticsPeriod < Long.MAX_VALUE)
					{
						dataModel.startStatisticsGathering(statisticsPeriod);
					}
					final DHTDataTableModel localDataTableModel = new DHTDataTableModel();
					final DHTDataTableModel getDataTableModel = new DHTDataTableModel();

					DHTDataModel getDataModel = new DHTDataModel();

					dataModel.addListener(new DHTDataEventListener()
					{

						//@Override
						public void rowAdded(final DHTDataRow dataRow)
						{
							SwingUtilities.invokeLater(new Runnable()
							{

								//@Override
								public void run()
								{
									localDataTableModel.addRow(dataRow);
								}
							});
						}

						//@Override
						public void rowRemoved(final DHTDataRow dataRow)
						{
							SwingUtilities.invokeLater(new Runnable()
							{

								//@Override
								public void run()
								{
									localDataTableModel.removeRow(dataRow);
									//getDataTableModel.removeRow(dataRow);
								}
							});
						}
					});

					getDataModel.addListener(new DHTDataEventListener()
					{

						//@Override
						public void rowAdded(final DHTDataRow dataRow)
						{
							SwingUtilities.invokeLater(new Runnable()
							{

								//@Override
								public void run()
								{
									getDataTableModel.addRow(dataRow);
								}
							});
						}

						//@Override
						public void rowRemoved(final DHTDataRow dataRow)
						{
							SwingUtilities.invokeLater(new Runnable()
							{

								//@Override
								public void run()
								{
									getDataTableModel.removeRow(dataRow);
								}
							});
						}
					});


					DHTStatistics statistics = null;
					if (statisticsPeriod < Long.MAX_VALUE)
					{
						statistics = new DHTStatistics(dataModel, nodeModel, network, scheduledExecutor, statisticsPeriod);
					}
					DHTFrame.createFrame("Узел DHT", nodeModel, dataModel, localDataTableModel, getDataTableModel, network, scheduledExecutor, statistics);
					NetworkListener networkListener = new Node(network, nodeModel, dataModel, getDataModel);
//                    networkListener.setGuiListener(getDataTableModel);
					network.addNetworkListener(networkListener);
					network.start();
					network.startStatisticGathering(statisticsPeriod);
					if (statisticsPeriod < Long.MAX_VALUE)
					{
						if (statistics != null)
						{
							statistics.startStatisticGathering();
						}
					}
					launcherDialog.dispose();
					try
					{
						network.sendPingRequest(network.getLocalAddress(), network.getLocalPort());
					}
					catch (IOException e)
					{
						throw new RuntimeException(e);
					}

				}
			}
		});
	}

}